/*
 * Copyright (c) 2012 Universidad Antonio de Nebrija.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Apache License v2.0
 * which accompanies this distribution, and is available at
 * http://www.apache.org/licenses/LICENSE-2.0.html
 * 
 * Contributors:
 *    Universidad Antonio de Nebrija - initial API, implementation and documentation
 */
package com.nebrija.riif.model;

import java.util.HashMap;
import java.util.Set;

/**
 * Root Class that will hold the elements (components, requirements and environments).
 */
public class RootClass implements RIIFElement {

	/** Unique standard name for this class objects */
	public static final String name="TOP";
	
	/** collection mapping names to RIIF elements */
	public HashMap<String,RIIFElement> elements = new HashMap<String,RIIFElement>();

	/** Singleton object */
	private static final RootClass singleton = new RootClass();
	
	/** Registry where the implementations of functions used in the files are registered*/
	private static final FunctionRegistry registry = new FunctionRegistry();
	
	/**
	 * Active global environment
	 */
	private Environment activeEnvironment = null;
	
	/**
	 * Global timeline
	 */
	private Timeline globalTimeline = null;
	
	private RootClass(){
	}
	
	public String getName(){
		return name;
	}
	
	/** Returns the singleton instance of this class */
	public static RootClass getInstance(){
		return singleton;
	}
	
	/** Incorporates a component, requirement or environment to the Root object */
	public String addElement(RIIFElement c){
		if (c==null){
			return "Null element";
		}
		if (c.getName()==null || c.getName().equals("")){
			return "Null element";
		}
		if (hasElement(c)){
			return "Already an element"; // TODO Internationalization
		}
		elements.put(c.getName(), c);
		return "";
	}
	
	/**
	 * Remove a component, requirement or environment from the Root object 
	 * @param c the element to be removed
	 * @return A string with an error message (blank if no error is found)
	 */
	public String removeElement(RIIFElement c){
		if (c==null){
			return "Null element";
		}
		if (c.getName()==null || c.getName().equals("")){
			return "Null element";
		}
		if (!hasElement(c)){
			return "Element not found"; // TODO Internationalization
		}
		elements.remove(c.getName());
		return "";
	}

	/**
	 * Remove a component, requirement or environment from the Root object 
	 * @param cName the name of the element to be removed
	 * @return A string with an error message (blank if no error is found)
	 */
	public String removeElement(String cName){
		if (cName==null || cName.equals("")){
			return "Null element";
		}
		if (elements.remove(cName)==null){
			return "Element not found"; // TODO Internationalization
		}
		return "";
	}
	
	public RIIFElement getElement (String cName){
		return elements.get(cName);
	}
	
	/**
	 * Checks if an element already exists in the Root object
	 * @param c the element to be checked
	 * @return true if the element is already in the root object, false otherwise.
	 */
	public boolean hasElement(RIIFElement c){
		if (elements.get(c.getName())!=null){
			return true;
		}
		return false;
	}
	
	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();
		Set<String> comps = elements.keySet();
		for (String name: comps){
			sb.append(elements.get(name).toString());
			sb.append("\n");
		}
		return sb.toString();
	}

	@Override
	public void resolve(RIIFElement container) {
		// Propagate to its elements
		Set<String> comps = elements.keySet();
		for (String name: comps){
			elements.get(name).resolve(this);
		}
	}


	@Override
	public void clear(RIIFElement container) {
		// Propagate to its elements
		Set<String> comps = elements.keySet();
		for (String name: comps){
			elements.get(name).clear(this);
		}
	}	
	
	/**
	 * Returns the registry where the implementation of the functions included in the RIIF
	 * files are stored
	 * @return the registry object
	 */
	public static FunctionRegistry getRegistry() {
		return registry;
	}

	public Environment getActiveEnvironment() {
		return activeEnvironment;
	}

	public void setActiveEnvironment(Environment activeEnvironment) {
		this.activeEnvironment = activeEnvironment;
	}

	public Timeline getGlobalTimeline() {
		return globalTimeline;
	}

	public void setGlobalTimeline(Timeline globalTimeline) {
		this.globalTimeline = globalTimeline;
	}

	@Override
	public int getChildCount() {
		return elements.size();
	}

@Override
	public Set<String> getElementNames() {
		return elements.keySet();
	}
	
}
